#include "dht11.h"
#include "iot_gpio.h"

// 优化的微秒级延时函数
static void Delay_us(unsigned int us)
{
    unsigned int i, j;
    for (i = 0; i < us; i++) {
        for (j = 0; j < 30; j++) {  // 再次增加循环次数提高精度
            __asm__ __volatile__("nop");
        }
    }
}

// DHT11硬件诊断函数
void DHT11_Diagnose(unsigned int gpio_pin)
{
    IotGpioValue level;
    int i;
    
    printf("\n========== DHT11硬件诊断开始 ==========\n");
    
    // 1. 检查GPIO初始化
    printf("1. 检查GPIO%d初始化...\n", gpio_pin);
    if (IoTGpioInit(gpio_pin) != 0) {
        printf("   [失败] GPIO%d初始化失败!\n", gpio_pin);
        printf("   可能原因: GPIO引脚号错误或硬件损坏\n");
        return;
    } else {
        printf("   [成功] GPIO%d初始化正常\n", gpio_pin);
    }
    
    // 2. 检查GPIO输出功能
    printf("2. 检查GPIO输出功能...\n");
    if (IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT) != 0) {
        printf("   [失败] GPIO%d设置为输出模式失败!\n", gpio_pin);
        return;
    }
    
    // 输出高电平
    if (IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1) != 0) {
        printf("   [失败] GPIO%d输出高电平失败!\n", gpio_pin);
        return;
    }
    usleep(100 * 1000);
    
    // 输出低电平
    if (IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE0) != 0) {
        printf("   [失败] GPIO%d输出低电平失败!\n", gpio_pin);
        return;
    }
    usleep(100 * 1000);
    
    // 恢复高电平
    if (IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1) != 0) {
        printf("   [失败] GPIO%d恢复高电平失败!\n", gpio_pin);
        return;
    }
    printf("   [成功] GPIO%d输出功能正常\n", gpio_pin);
    
    // 3. 检查GPIO输入功能
    printf("3. 检查GPIO输入功能...\n");
    if (IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_IN) != 0) {
        printf("   [失败] GPIO%d设置为输入模式失败!\n", gpio_pin);
        return;
    }
    
    // 读取输入电平
    if (IoTGpioGetInputVal(gpio_pin, &level) != 0) {
        printf("   [失败] GPIO%d读取输入电平失败!\n", gpio_pin);
        return;
    }
    printf("   [成功] GPIO%d输入功能正常，当前电平: %s\n", 
           gpio_pin, (level == IOT_GPIO_VALUE1) ? "高" : "低");
    
    // 4. 检查DHT11通信
    printf("4. 检查DHT11通信...\n");
    printf("   发送启动信号...\n");
    
    // 设置为输出模式
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT);
    
    // 发送启动信号
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE0); // 拉低
    usleep(20 * 1000);                              // 保持至少18ms
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1); // 拉高
    Delay_us(40);                                   // 等待30-40us
    
    // 设置为输入模式，等待DHT11响应
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_IN);
    
    // 等待DHT11拉低（响应信号）
    printf("   等待DHT11响应...\n");
    for (i = 0; i < 100; i++) {
        IoTGpioGetInputVal(gpio_pin, &level);
        if (level == IOT_GPIO_VALUE0) {
            printf("   [成功] 检测到DHT11响应信号(低电平)，延时: %d us\n", i);
            break;
        }
        Delay_us(1);
    }
    
    if (i >= 100) {
        printf("   [失败] 未检测到DHT11响应信号!\n");
        printf("   可能原因:\n");
        printf("   1. DHT11未正确连接或损坏\n");
        printf("   2. DATA引脚未连接上拉电阻\n");
        printf("   3. 电源电压不稳定\n");
        printf("   4. 连接线过长或受到干扰\n");
        printf("========== DHT11硬件诊断结束 ==========\n");
        return;
    }
    
    // 等待DHT11拉高（准备发送数据）
    for (i = 0; i < 100; i++) {
        IoTGpioGetInputVal(gpio_pin, &level);
        if (level == IOT_GPIO_VALUE1) {
            printf("   [成功] 检测到DHT11准备信号(高电平)，延时: %d us\n", i);
            break;
        }
        Delay_us(1);
    }
    
    if (i >= 100) {
        printf("   [失败] 未检测到DHT11准备信号!\n");
        printf("========== DHT11硬件诊断结束 ==========\n");
        return;
    }
    
    printf("   [成功] DHT11通信正常\n");
    printf("========== DHT11硬件诊断结束 ==========\n");
    
    // 恢复GPIO状态
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1);
}

// DHT11初始化
void DHT11_Init(unsigned int gpio_pin)
{
    // 运行硬件诊断
    DHT11_Diagnose(gpio_pin);
    
    // 初始化GPIO
    IoTGpioInit(gpio_pin);
    // 设置为输出模式
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT);
    // 输出高电平
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1);
    // 等待DHT11稳定
    usleep(2000 * 1000); // 增加到2秒，确保DHT11完全上电稳定
    
    printf("DHT11初始化完成，GPIO引脚: %d\n", gpio_pin);
}

// 优化的启动DHT11函数
static int DHT11_Start(unsigned int gpio_pin)
{
    int retry = 0;
    IotGpioValue level;
    
    // 禁用中断，确保时序准确
    // 注意：在实际产品中，这可能会影响系统其他功能
    // unsigned long irq_save = 0;
    // irq_save = LOS_IntLock();
    
    // 设置为输出模式
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT);
    
    // 主机发送起始信号 - 严格按照DHT11时序要求
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE0); // 拉低
    usleep(20 * 1000);                              // 保持至少18ms，确保DHT11检测到
    IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1); // 拉高
    Delay_us(30);                                   // 等待20-40us，这里使用30us
    
    // 设置为输入模式，等待DHT11响应
    IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_IN);
    
    // 等待DHT11拉低（响应信号）
    retry = 0;
    while (1) {
        IoTGpioGetInputVal(gpio_pin, &level);
        if (level == IOT_GPIO_VALUE0) {
            break;
        }
        retry++;
        if (retry > 200) {  // 增加超时时间
            printf("DHT11没有响应，超时1\n");
            // LOS_IntRestore(irq_save);  // 恢复中断
            return -1; // 超时，DHT11没有响应
        }
        Delay_us(1);
    }
    
    // 等待DHT11拉高（准备发送数据）
    retry = 0;
    while (1) {
        IoTGpioGetInputVal(gpio_pin, &level);
        if (level == IOT_GPIO_VALUE1) {
            break;
        }
        retry++;
        if (retry > 200) {  // 增加超时时间
            printf("DHT11没有拉高，超时2\n");
            // LOS_IntRestore(irq_save);  // 恢复中断
            return -1; // 超时
        }
        Delay_us(1);
    }
    
    // 等待DHT11再次拉低（开始发送数据）
    retry = 0;
    while (1) {
        IoTGpioGetInputVal(gpio_pin, &level);
        if (level == IOT_GPIO_VALUE0) {
            break;
        }
        retry++;
        if (retry > 200) {  // 增加超时时间
            printf("DHT11没有拉低，超时3\n");
            // LOS_IntRestore(irq_save);  // 恢复中断
            return -1; // 超时
        }
        Delay_us(1);
    }
    
    // LOS_IntRestore(irq_save);  // 恢复中断
    return 0; // 成功启动
}

// 优化的读取一个字节函数
static unsigned char DHT11_Read_Byte(unsigned int gpio_pin)
{
    unsigned char i, data = 0;
    IotGpioValue level;
    int retry;
    int high_time;
    
    for (i = 0; i < 8; i++) {
        // 等待前置低电平结束
        retry = 0;
        while (1) {
            IoTGpioGetInputVal(gpio_pin, &level);
            if (level == IOT_GPIO_VALUE1) {
                break;
            }
            retry++;
            if (retry > 200) {  // 增加超时时间
                return 0; // 超时
            }
            Delay_us(1);
        }
        
        // 测量高电平持续时间来判断数据位
        high_time = 0;
        while (1) {
            IoTGpioGetInputVal(gpio_pin, &level);
            if (level == IOT_GPIO_VALUE0) {
                break;
            }
            high_time++;
            if (high_time > 200) {  // 增加超时时间
                return 0; // 超时
            }
            Delay_us(1);
        }
        
        // 根据高电平持续时间判断数据位
        // 通常，0位的高电平持续约26-28us，1位的高电平持续约70us
        if (high_time > 35) {  // 阈值设为35us
            data |= (1 << (7 - i));
        }
    }
    
    return data;
}

// 打印调试信息的辅助函数
static void PrintByteDebug(const char* name, unsigned char value)
{
    printf("%s: %d (0x%02X), 二进制: ", name, value, value);
    for (int i = 7; i >= 0; i--) {
        printf("%d", (value >> i) & 0x01);
    }
    printf("\n");
}

// 读取DHT11数据，增加重试机制和更详细的调试信息
DHT11_Data_TypeDef DHT11_Read_Data(unsigned int gpio_pin)
{
    DHT11_Data_TypeDef data = {0.0, 0.0, -1}; // 初始化为错误状态
    unsigned char buf[5] = {0};
    unsigned char check_sum;
    int retry_count = 0;
    const int max_retries = 5;  // 增加最大重试次数
    
    while (retry_count < max_retries) {
        // 启动DHT11
        if (DHT11_Start(gpio_pin) != 0) {
            printf("DHT11启动失败，重试 %d/%d\n", retry_count + 1, max_retries);
            retry_count++;
            usleep(2000 * 1000);  // 失败后等待2秒再重试
            continue;
        }
        
        // 读取5个字节数据
        buf[0] = DHT11_Read_Byte(gpio_pin); // 湿度整数部分
        buf[1] = DHT11_Read_Byte(gpio_pin); // 湿度小数部分
        buf[2] = DHT11_Read_Byte(gpio_pin); // 温度整数部分
        buf[3] = DHT11_Read_Byte(gpio_pin); // 温度小数部分
        buf[4] = DHT11_Read_Byte(gpio_pin); // 校验和
        
        // 设置输出高电平，结束通信
        IoTGpioSetDir(gpio_pin, IOT_GPIO_DIR_OUT);
        IoTGpioSetOutputVal(gpio_pin, IOT_GPIO_VALUE1);
        
        // 打印每个字节的详细信息用于调试
        printf("DHT11读取的原始数据:\n");
        PrintByteDebug("湿度整数", buf[0]);
        PrintByteDebug("湿度小数", buf[1]);
        PrintByteDebug("温度整数", buf[2]);
        PrintByteDebug("温度小数", buf[3]);
        PrintByteDebug("校验和", buf[4]);
        
        // 校验数据
        check_sum = buf[0] + buf[1] + buf[2] + buf[3];
        printf("计算的校验和: %d (0x%02X), 接收的校验和: %d (0x%02X)\n", 
               check_sum, check_sum, buf[4], buf[4]);
               
        if (check_sum != buf[4]) {
            printf("DHT11数据校验失败！计算值:%d, 接收值:%d\n", check_sum, buf[4]);
            
            // 检查数据是否合理，即使校验和不匹配
            if (buf[0] >= 20 && buf[0] <= 90 &&  // 湿度通常在20%-90%范围内
                buf[2] >= 0 && buf[2] <= 50) {   // 温度通常在0-50°C范围内
                
                printf("虽然校验和不匹配，但数据看起来合理，尝试使用...\n");
                
                // 填充数据
                data.humidity = (float)buf[0] + (float)buf[1] / 10.0;
                data.temperature = (float)buf[2] + (float)buf[3] / 10.0;
                data.status = 0; // 读取成功
                
                printf("DHT11读取成功(忽略校验): 温度=%.1f℃, 湿度=%.1f%%\n", 
                       data.temperature, data.humidity);
                return data;
            }
            
            retry_count++;
            usleep(2000 * 1000);  // 失败后等待2秒再重试
            continue;
        }
        
        // 数据有效性检查
        if (buf[0] == 0 && buf[2] == 0) {
            printf("DHT11数据无效，全为0\n");
            retry_count++;
            usleep(2000 * 1000);  // 失败后等待2秒再重试
            continue;
        }
        
        // 填充数据
        data.humidity = (float)buf[0] + (float)buf[1] / 10.0;
        data.temperature = (float)buf[2] + (float)buf[3] / 10.0;
        data.status = 0; // 读取成功
        
        printf("DHT11读取成功: 温度=%.1f℃, 湿度=%.1f%%\n", data.temperature, data.humidity);
        return data;
    }
    
    printf("DHT11读取失败，已达到最大重试次数\n");
    return data;
}

// 添加DHT11测试函数
void DHT11_Test(unsigned int gpio_pin, int test_count)
{
    int i;
    int success_count = 0;
    DHT11_Data_TypeDef dht11_data;
    
    printf("\n========== DHT11测试开始 ==========\n");
    printf("将连续读取DHT11传感器 %d 次\n", test_count);
    
    // 初始化DHT11
    printf("初始化DHT11传感器...\n");
    DHT11_Init(gpio_pin);
    
    // 等待DHT11稳定
    printf("等待DHT11稳定...\n");
    sleep(2);
    
    // 连续读取多次
    for (i = 0; i < test_count; i++) {
        printf("\n----- 测试 %d/%d -----\n", i + 1, test_count);
        
        // 读取DHT11数据
        dht11_data = DHT11_Read_Data(gpio_pin);
        
        // 检查读取结果
        if (dht11_data.status == 0) {
            printf("测试 %d 成功: 温度=%.1f℃, 湿度=%.1f%%\n", 
                   i + 1, dht11_data.temperature, dht11_data.humidity);
            success_count++;
        } else {
            printf("测试 %d 失败\n", i + 1);
        }
        
        // 等待下一次测试
        if (i < test_count - 1) {
            printf("等待下一次测试...\n");
            sleep(3);  // 每次测试间隔3秒
        }
    }
    
    // 打印测试结果统计
    printf("\n========== DHT11测试结果 ==========\n");
    printf("总测试次数: %d\n", test_count);
    printf("成功次数: %d\n", success_count);
    printf("失败次数: %d\n", test_count - success_count);
    printf("成功率: %.1f%%\n", (float)success_count / test_count * 100);
    printf("==================================\n");
} 